package com.duan.laugh.file.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.duan.laugh.common.core.exception.CheckedException;
import com.duan.laugh.common.core.util.Assert;
import com.duan.laugh.starter.minio.core.MinioTemplate;
import com.duan.laugh.file.api.pojo.eneity.File;
import com.duan.laugh.file.mapper.FileMapper;
import com.duan.laugh.file.service.FileService;
import com.duan.laugh.file.util.EnumCodeMessage;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.multipart.MultipartFile;

/**
 * 文件service实现
 *
 * @author duanjw
 */
@Service
public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements FileService {

    @Autowired
    private MinioTemplate template;

    /**
     * 上传文件
     *
     * @param file       文件
     * @param bucketName bucket名称
     * @param filename   文件名称
     * @return
     */
    @Override
    @SneakyThrows
    public File uploadFile(@RequestBody MultipartFile file, String bucketName, String filename) {
        final String md5 = DigestUtil.md5Hex(file.getInputStream());
        final String fileOriginalFilename = file.getOriginalFilename();
        File dbFile = getByMd5(md5);
        // 文件在bucket已经存在，在数据库复制该文件的数据，并返回文件信息
        if (null != dbFile && bucketName.equals(dbFile.getBucketName())) {
            dbFile.setId(null).setCreateTime(DateUtil.date()).setType(StrUtil.concat(false, getFileType(fileOriginalFilename))).setName(filename);
            dbFile.insert();
            return dbFile;
        }
        // 文件不在当前bucket中，复制到本bucket中
        if (null != dbFile) {
            final String newFilename = dbFile.getFilename();
            template.copyFile(dbFile.getBucketName(), newFilename, bucketName, newFilename);
        } else {
            // 否则上传文件，并保存到数据库
            String newFilename = StrUtil.concat(true, md5, getFileType(fileOriginalFilename));
            template.uploadFile(bucketName, newFilename, file.getInputStream(), file.getSize(), file.getContentType());
        }
        // 保存文件到数据库
        dbFile = new File().setCreateTime(DateUtil.date()).setMd5(md5).setBucketName(bucketName).setType(StrUtil.concat(false, getFileType(fileOriginalFilename))).setName(filename);
        dbFile.insert();
        return dbFile;
    }

    /**
     * 根据md5查看文件
     *
     * @param md5
     * @return
     */
    @Override
    public File getByMd5(String md5) {
        return getOne(new LambdaQueryWrapper<File>().eq(File::getMd5, md5));
    }

    /**
     * 获取文件类型包括.
     * 如果文件没有类型，返回""
     *
     * @param filename
     * @return
     */
    private String getFileType(String filename) {
        final String type = FileUtil.extName(filename);
        return StrUtil.isBlank(type) ? "" : StrUtil.concat(true, StrUtil.DOT, type);
    }

    /**
     * 根据id删除文件
     * @param bucketName
     * @param id
     */
    @Override
    @SneakyThrows
    public boolean deleteFile(String bucketName, Long id) {
        final File dbFile = getById(id);
        Assert.isNull(dbFile, EnumCodeMessage.FILE_NOT_FOUND);
        // 不是该bucket中的文件无法访问
        if(!bucketName.equals(dbFile.getBucketName())){
            throw new CheckedException(EnumCodeMessage.FILE_ACCESS_DENIED);
        }
        // 删除文件&删除数据库的记录
        template.deleteFile(dbFile.getBucketName(), dbFile.getFilename());
        return removeById(id);
    }
}
